<?php
namespace my;

/**
 * 经纬度
 * @package my
 */
class Lnglat
{
    public function __construct() {}

    /**
     * BD-09(百度)坐标转换成GCJ-02(火星，高德)坐标.
     * @param float $bd_lng 百度经度
     * @param float $bd_lat 百度纬度
     * @return array
     */
    public static function bd2gd($bd_lng, $bd_lat){
        $x_pi = 3.14159265358979324 * 3000.0 / 180.0;
        $x = $bd_lng - 0.0065;
        $y = $bd_lat - 0.006;
        $z = sqrt($x * $x + $y * $y) - 0.00002 * sin($y * $x_pi);
        $theta  = atan2($y, $x) - 0.000003 * cos($x * $x_pi);
        $gd_lng = round($z * cos($theta), 6);
        $gd_lat = round($z * sin($theta), 6);
        return [$gd_lng, $gd_lat];
    }

    /**
     * GCJ-02(火星，高德)坐标转换成BD-09(百度)坐标.
     * @param float $gd_lng 高德经度
     * @param float $gd_lat 高德纬度
     * @return array
     */
    public static function gd2bd($gd_lng, $gd_lat)
    {
        $x_pi = 3.14159265358979324 * 3000.0 / 180.0;
        $x = $gd_lng;
        $y = $gd_lat;
        $z = sqrt($x * $x + $y * $y) - 0.00002 * sin($y * $x_pi);
        $theta  = atan2($y, $x) - 0.000003 * cos($x * $x_pi);
        $bd_lng = round($z * cos($theta) + 0.0065, 6);
        $bd_lat = round($z * sin($theta) + 0.006, 6);
        return [$bd_lng, $bd_lat];
    }

    /**
     * 计算两个经纬度之间的距离
     * @param array $point_user 用户经纬度;
     * @param array $point_store 订餐点经纬度;
     * @return string
     */
    public static function getPointDistance($point_user = [], $point_store = []) 
    {
        // 将角度转为狐度
        $radLat1 = deg2rad($point_user[0]); //deg2rad()函数将角度转换为弧度
        $radLat2 = deg2rad($point_store[0]);
        $radLng1 = deg2rad($point_user[1]);
        $radLng2 = deg2rad($point_store[1]);
        $a = $radLat1 - $radLat2;
        $b = $radLng1 - $radLng2;
        $s = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2))) * 6378.137 * 1000;
        return $s;
    }

    /**
     * 判断一个坐标是否在一个由多个坐标围成的多边形内
     * 基本思想是利用射线法，计算射线与多边形各边的交点，如果是偶数，则点在多边形外，否则
     * 在多边形内。还会考虑一些特殊情况，如点在多边形顶点上，点在多边形边上等特殊情况。
     * @param array $point 指定点坐标 [121.427417,31.20357];前经度后纬度
     * @param array $points 多边形坐标,顺时针方向 [[121.23036,31.218609],[121.233666,31.210579],[121.247177,31.206749]];
     * @return bool
     */
    public static function isPointInPolygon($point = [], $points = []) {
        $N = count($points);
        $boundOrVertex  = true;//如果点位于多边形的顶点或边上，也算做点在多边形内，直接返回true
        $intersectCount = 0;//cross points count of x
        $precision = 2e-10;//浮点类型计算时候与0比较时候的容差
        $p1 = 0;//neighbour bound vertices
        $p2 = 0;
        $p  = $point;//测试点
        $p1 = $points[0];//left vertex
        //check all rays
        for ($i = 1; $i <= $N; ++$i) {
            if ($p[0] == $p1[0] && $p[1] == $p1[1]) {
                return $boundOrVertex;//p is an vertex
            }
            $p2 = $points[$i % $N];//right vertex
            //ray is outside of our interests
            if ($p[1] < min($p1[1], $p2[1]) || $p[1] > max($p1[1], $p2[1])) {
                $p1 = $p2;
                continue;//next ray left point
            }
            //ray is crossing over by the algorithm (common part of)
            if ($p[1] > min($p1[1], $p2[1]) && $p[1] < max($p1[1], $p2[1])) {
                if($p[0] <= max($p1[0], $p2[0])){//x is before of ray
                    if ($p1[1] == $p2[1] && $p[0] >= min($p1[0], $p2[0])) {//overlies on a horizontal ray
                        return $boundOrVertex;
                    }
                    if ($p1[0] == $p2[0]) {//ray is vertical
                        if ($p1[0] == $p[0]) {//overlies on a vertical ray
                            return $boundOrVertex;
                        } else {//before ray
                            ++$intersectCount;
                        }
                    } else {//cross point on the left side
                        //cross point of lng
                        $xinters = ($p[1] - $p1[1]) * ($p2[0] - $p1[0]) / ($p2[1] - $p1[1]) + $p1[0];
                        if (abs($p[0] - $xinters) < $precision) {//overlies on a ray
                            return $boundOrVertex;
                        }
                        if ($p[0] < $xinters) {//before ray
                            ++$intersectCount;
                        }
                    }
                }
            } else {//special case when ray is crossing through the vertex
                if ($p[1] == $p2[1] && $p[0] <= $p2[0]) {//p crossing over p2
                    $p3 = $points[($i+1) % $N];//next vertex
                    //p.lat lies between p1.lat & p3.lat
                    if ($p[1] >= min($p1[1], $p3[1]) && $p[1] <= max($p1[1], $p3[1])) {
                        ++$intersectCount;
                    } else {
                        $intersectCount += 2;
                    }
                }
            }
            $p1 = $p2;//next ray left point
        }
        //偶数在多边形外，奇数在多边形内
        return $intersectCount % 2 == 0 ? false : true;
    }
}